﻿using static Vanara.PInvoke.Gdi32;

namespace Vanara.PInvoke;

public static partial class User32
{
	/// <summary>The type of information to retrieve.</summary>
	[PInvokeData("wingdi.h", MSDNShortId = "5ec7f521-28b5-4922-a3fc-aa4433de69e0")]
	[Flags]
	public enum QDC
	{
		/// <summary>The caller requests the table sizes to hold all the possible path combinations.</summary>
		QDC_ALL_PATHS = 0x00000001,

		/// <summary>The caller requests the table sizes to hold only active paths.</summary>
		QDC_ONLY_ACTIVE_PATHS = 0x00000002,

		/// <summary>
		/// The caller requests the table sizes to hold the active paths as defined in the persistence database for the currently
		/// connected monitors.
		/// </summary>
		QDC_DATABASE_CURRENT = 0x00000004,

		/// <summary>Undocumented.</summary>
		QDC_VIRTUAL_MODE_AWARE = 0x00000010,

		/// <summary>Undocumented.</summary>
		QDC_INCLUDE_HMD = 0x00000020,
	}

	/// <summary>Flag values that indicates the behavior of SetDisplayConfig.</summary>
	[PInvokeData("wingdi.h", MSDNShortId = "9f649fa0-ffb2-44c6-9a66-049f888e3b04")]
	[Flags]
	public enum SDC
	{
		/// <summary>The caller requests the last internal configuration from the persistence database.</summary>
		SDC_TOPOLOGY_INTERNAL = 0x00000001,

		/// <summary>The caller requests the last clone configuration from the persistence database.</summary>
		SDC_TOPOLOGY_CLONE = 0x00000002,

		/// <summary>The caller requests the last extended configuration from the persistence database.</summary>
		SDC_TOPOLOGY_EXTEND = 0x00000004,

		/// <summary>The caller requests the last external configuration from the persistence database.</summary>
		SDC_TOPOLOGY_EXTERNAL = 0x00000008,

		/// <summary>
		/// The caller provides the path data so the function only queries the persistence database to find and use the source and target mode.
		/// </summary>
		SDC_TOPOLOGY_SUPPLIED = 0x00000010,

		/// <summary>
		/// The caller requests a combination of all four SDC_TOPOLOGY_XXX configurations. This value informs the API to set the last
		/// known display configuration for the current connected monitors.
		/// </summary>
		SDC_USE_DATABASE_CURRENT = SDC_TOPOLOGY_INTERNAL | SDC_TOPOLOGY_CLONE | SDC_TOPOLOGY_EXTEND | SDC_TOPOLOGY_EXTERNAL,

		/// <summary>
		/// The topology, source, and target mode information that are supplied in the pathArray and the modeInfoArray parameters are
		/// used, rather than looking up the configuration in the database.
		/// </summary>
		SDC_USE_SUPPLIED_DISPLAY_CONFIG = 0x00000020,

		/// <summary>
		/// The system tests for the requested topology, source, and target mode information to determine whether it can be set.
		/// </summary>
		SDC_VALIDATE = 0x00000040,

		/// <summary>The resulting topology, source, and target mode is set.</summary>
		SDC_APPLY = 0x00000080,

		/// <summary>
		/// A modifier to the SDC_APPLY flag. This causes the change mode to be forced all the way down to the driver for each active display.
		/// </summary>
		SDC_NO_OPTIMIZATION = 0x00000100,

		/// <summary>The resulting topology, source, and target mode are saved to the database.</summary>
		SDC_SAVE_TO_DATABASE = 0x00000200,

		/// <summary>
		/// If required, the function can modify the specified source and target mode information in order to create a functional display
		/// path set.
		/// </summary>
		SDC_ALLOW_CHANGES = 0x00000400,

		/// <summary>
		/// When the function processes a SDC_TOPOLOGY_XXX request, it can force path persistence on a target to satisfy the request if
		/// necessary. For information about the other flags that this flag can be combined with, see the following list.
		/// </summary>
		SDC_PATH_PERSIST_IF_REQUIRED = 0x00000800,

		/// <summary>
		/// The caller requests that the driver is given an opportunity to update the GDI mode list while SetDisplayConfig sets the new
		/// display configuration. This flag value is only valid when the SDC_USE_SUPPLIED_DISPLAY_CONFIG and SDC_APPLY flag values are
		/// also specified.
		/// </summary>
		SDC_FORCE_MODE_ENUMERATION = 0x00001000,

		/// <summary>
		/// A modifier to the SDC_TOPOLOGY_SUPPLIED flag that indicates that SetDisplayConfig should ignore the path order of the
		/// supplied topology when searching the database. When this flag is set, the topology set is the most recent topology that
		/// contains all the paths regardless of the path order.
		/// </summary>
		SDC_ALLOW_PATH_ORDER_CHANGES = 0x00002000,

		/// <summary>Undocumented.</summary>
		SDC_VIRTUAL_MODE_AWARE = 0x00008000,
	}

	/// <summary>The <c>DisplayConfigGetDeviceInfo</c> function retrieves display configuration information about the device.</summary>
	/// <param name="requestPacket">
	/// A pointer to a DISPLAYCONFIG_DEVICE_INFO_HEADER structure. This structure contains information about the request, which includes
	/// the packet type in the <c>type</c> member. The type and size of additional data that <c>DisplayConfigGetDeviceInfo</c> returns
	/// after the header structure depend on the packet type.
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags specified are invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_INSUFFICIENT_BUFFER</term>
	/// <term>The size of the packet that the caller passes is not big enough for the information that the caller requests.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// Use the <c>DisplayConfigGetDeviceInfo</c> function to obtain additional information about a source or target for an adapter, such
	/// as the display name, the preferred display mode, and source device name.
	/// </para>
	/// <para>
	/// The caller can call <c>DisplayConfigGetDeviceInfo</c> to obtain more friendly names to display in the user interface. The caller
	/// can obtain names for the adapter, the source, and the target. The caller can also call <c>DisplayConfigGetDeviceInfo</c> to
	/// obtain the best resolution of the connected display device.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-displayconfiggetdeviceinfo LONG
	// DisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEADER *requestPacket );
	[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("winuser.h", MSDNShortId = "249dcb1a-4ce3-4478-8331-fb81e91313b0")]
	public static extern Win32Error DisplayConfigGetDeviceInfo(IntPtr requestPacket);

	/// <summary>The <c>DisplayConfigGetDeviceInfo</c> function retrieves display configuration information about the device.</summary>
	/// <typeparam name="T">The type of structure to return. This must match the type supported by <paramref name="type"/>.</typeparam>
	/// <param name="adapterId">
	/// A locally unique identifier (LUID) that identifies the adapter that the device information packet refers to.
	/// </param>
	/// <param name="id">
	/// The source or target identifier to get or set the device information for. The meaning of this identifier is related to the type
	/// of information being requested. For example, in the case of DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, this is the source identifier.
	/// </param>
	/// <param name="type">
	/// A DISPLAYCONFIG_DEVICE_INFO_TYPE enumerated value that determines the type of device information to retrieve or set. The
	/// remainder of the packet for the retrieve or set operation follows immediately after the DISPLAYCONFIG_DEVICE_INFO_HEADER
	/// structure. Leave this value as the default (0) to have the value inferred from <typeparamref name="T"/>.
	/// </param>
	/// <returns>The value of type <typeparamref name="T"/> for the information provided.</returns>
	/// <exception cref="ArgumentException">Request type does not match type param value.</exception>
	public static T DisplayConfigGetDeviceInfo<T>(ulong adapterId, uint id, DISPLAYCONFIG_DEVICE_INFO_TYPE type = 0) where T : struct, IDisplayConfig
	{
		if (type == 0)
		{
			if (!CorrespondingTypeAttribute.CanGet<T, DISPLAYCONFIG_DEVICE_INFO_TYPE>(out type))
				throw new ArgumentException("Unable to find enum value matching supplied type param.");
		}
		else if (!CorrespondingTypeAttribute.CanGet(type, typeof(T)))
			throw new ArgumentException("Request type does not match type param value.");
		DISPLAYCONFIG_DEVICE_INFO_HEADER hdr = new() { size = (uint)Marshal.SizeOf(typeof(T)), type = type, adapterId = adapterId, id = id };
		using var mem = new SafeCoTaskMemStruct<T>((int)hdr.size);
		Marshal.StructureToPtr(hdr, (IntPtr)mem, false);
		DisplayConfigGetDeviceInfo(mem).ThrowIfFailed();
		return mem.Value;
	}

	/// <summary>The <c>DisplayConfigSetDeviceInfo</c> function sets the properties of a target.</summary>
	/// <param name="setPacket">
	/// A pointer to a DISPLAYCONFIG_DEVICE_INFO_HEADER structure that contains information to set for the device. The type and size of
	/// additional data that <c>DisplayConfigSetDeviceInfo</c> uses for the configuration comes after the header structure. This
	/// additional data depends on the packet type, as specified by the <c>type</c> member of DISPLAYCONFIG_DEVICE_INFO_HEADER. For
	/// example, if the caller wants to change the boot persistence, that caller allocates and fills a
	/// DISPLAYCONFIG_SET_TARGET_PERSISTENCE structure and passes a pointer to this structure in setPacket. Note that the first member of
	/// the DISPLAYCONFIG_SET_TARGET_PERSISTENCE structure is the DISPLAYCONFIG_DEVICE_INFO_HEADER.
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags specified are invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_INSUFFICIENT_BUFFER</term>
	/// <term>The size of the packet that the caller passes is not big enough.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// <c>DisplayConfigSetDeviceInfo</c> can currently only be used to start and stop boot persisted force projection on an analog
	/// target. For more information about boot persistence, see Forced Versus Connected Targets.
	/// </para>
	/// <para>
	/// <c>DisplayConfigSetDeviceInfo</c> can only be used to set DISPLAYCONFIG_DEVICE_INFO_SET_XXX type of information.
	/// <c>DisplayConfigSetDeviceInfo</c> fails if the <c>type</c> member of DISPLAYCONFIG_DEVICE_INFO_HEADER is set to one of the
	/// DISPLAYCONFIG_DEVICE_INFO_GET_XXX values.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-displayconfigsetdeviceinfo LONG
	// DisplayConfigSetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEADER *setPacket );
	[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("winuser.h", MSDNShortId = "4050b1f0-a588-427c-a0df-eefdc488fc20")]
	public static extern Win32Error DisplayConfigSetDeviceInfo(IntPtr setPacket);

	/// <summary>The <c>DisplayConfigSetDeviceInfo</c> function sets the properties of a target.</summary>
	/// <typeparam name="T">The type of the value to set.</typeparam>
	/// <param name="value">Contains information to set for the device.</param>
	/// <exception cref="ArgumentException">Supplied type does not match valid set value.</exception>
	public static void DisplayConfigSetDeviceInfo<T>(T value) where T : struct
	{
		if (!CorrespondingTypeAttribute.CanSet(typeof(DISPLAYCONFIG_DEVICE_INFO_TYPE), typeof(T))) throw new ArgumentException("Supplied type does not match valid set value.");
		var mem = SafeHGlobalHandle.CreateFromStructure(value);
		DisplayConfigSetDeviceInfo((IntPtr)mem).ThrowIfFailed();
	}

	/// <summary>
	/// The <c>GetDisplayConfigBufferSizes</c> function retrieves the size of the buffers that are required to call the
	/// QueryDisplayConfig function.
	/// </summary>
	/// <param name="flags">
	/// <para>The type of information to retrieve. The value for the Flags parameter must be one of the following values.</para>
	/// <para>QDC_ALL_PATHS</para>
	/// <para>The caller requests the table sizes to hold all the possible path combinations.</para>
	/// <para>QDC_ONLY_ACTIVE_PATHS</para>
	/// <para>The caller requests the table sizes to hold only active paths.</para>
	/// <para>QDC_DATABASE_CURRENT</para>
	/// <para>
	/// The caller requests the table sizes to hold the active paths as defined in the persistence database for the currently connected monitors.
	/// </para>
	/// </param>
	/// <param name="numPathArrayElements">
	/// Pointer to a variable that receives the number of elements in the path information table. The pNumPathArrayElements parameter
	/// value is then used by a subsequent call to the QueryDisplayConfig function. This parameter cannot be <c>NULL</c>.
	/// </param>
	/// <param name="numModeInfoArrayElements">
	/// Pointer to a variable that receives the number of elements in the mode information table. The pNumModeInfoArrayElements parameter
	/// value is then used by a subsequent call to the QueryDisplayConfig function. This parameter cannot be <c>NULL</c>.
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags that are specified is invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// Given the current display path configuration and the requested flags, <c>GetDisplayConfigBufferSizes</c> returns the size of the
	/// path and mode tables that are required to store the information. <c>GetDisplayConfigBufferSizes</c> can return values that are
	/// slightly larger than are actually required because it determines that all source and target paths are valid; whereas, the driver
	/// might place some restrictions on the possible combinations.
	/// </para>
	/// <para>
	/// As <c>GetDisplayConfigBufferSizes</c> can only determine the required array size of that moment in time, it is possible that
	/// between calls to <c>GetDisplayConfigBufferSizes</c> and QueryDisplayConfig the system configuration has changed and the provided
	/// array sizes are no longer sufficient to store the new path data.
	/// </para>
	/// <para>
	/// If a caller is aware that it must enable additional sources and targets, the caller can allocate a larger mode information array
	/// than is returned from <c>GetDisplayConfigBufferSizes</c> so that it has the space to add the additional source and target modes
	/// after calling <c>QueryDisplayConfig</c> and before calling SetDisplayConfig.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getdisplayconfigbuffersizes LONG
	// GetDisplayConfigBufferSizes( UINT32 flags, UINT32 *numPathArrayElements, UINT32 *numModeInfoArrayElements );
	[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("winuser.h", MSDNShortId = "5ec7f521-28b5-4922-a3fc-aa4433de69e0")]
	public static extern Win32Error GetDisplayConfigBufferSizes(QDC flags, out uint numPathArrayElements, out uint numModeInfoArrayElements);

	/// <summary>
	/// The <c>QueryDisplayConfig</c> function retrieves information about all possible display paths for all display devices, or views,
	/// in the current setting.
	/// </summary>
	/// <param name="flags">
	/// <para>The type of information to retrieve. The value for the Flags parameter must be one of the following values.</para>
	/// <para>QDC_ALL_PATHS</para>
	/// <para>All the possible path combinations of sources to targets.</para>
	/// <para>
	/// <c>Note</c> In the case of any temporary modes, the QDC_ALL_PATHS setting means the mode data returned may not be the same as
	/// that which is stored in the persistence database.
	/// </para>
	/// <para>QDC_ONLY_ACTIVE_PATHS</para>
	/// <para>Currently active paths only.</para>
	/// <para>
	/// <c>Note</c> In the case of any temporary modes, the QDC_ONLY_ACTIVE_PATHS setting means the mode data returned may not be the
	/// same as that which is stored in the persistence database.
	/// </para>
	/// <para>QDC_DATABASE_CURRENT</para>
	/// <para>Active path as defined in the CCD database for the currently connected displays.</para>
	/// </param>
	/// <param name="numPathArrayElements">
	/// Pointer to a variable that contains the number of elements in pPathInfoArray. This parameter cannot be <c>NULL</c>. If
	/// <c>QueryDisplayConfig</c> returns ERROR_SUCCESS, pNumPathInfoElements is updated with the number of valid entries in pPathInfoArray.
	/// </param>
	/// <param name="pathArray">
	/// Pointer to a variable that contains an array of DISPLAYCONFIG_PATH_INFO elements. Each element in pPathInfoArray describes a
	/// single path from a source to a target. The source and target mode information indexes are only valid in combination with the
	/// pmodeInfoArray tables that are returned for the API at the same time. This parameter cannot be <c>NULL</c>. The pPathInfoArray is
	/// always returned in path priority order. For more information about path priority order, see Path Priority Order.
	/// </param>
	/// <param name="numModeInfoArrayElements">
	/// Pointer to a variable that specifies the number in element of the mode information table. This parameter cannot be <c>NULL</c>.
	/// If <c>QueryDisplayConfig</c> returns ERROR_SUCCESS, pNumModeInfoArrayElements is updated with the number of valid entries in pModeInfoArray.
	/// </param>
	/// <param name="modeInfoArray">
	/// Pointer to a variable that contains an array of DISPLAYCONFIG_MODE_INFO elements. This parameter cannot be <c>NULL</c>.
	/// </param>
	/// <param name="currentTopologyId">
	/// <para>
	/// Pointer to a variable that receives the identifier of the currently active topology in the CCD database. For a list of possible
	/// values, see the DISPLAYCONFIG_TOPOLOGY_ID enumerated type.
	/// </para>
	/// <para>The pCurrentTopologyId parameter is only set when the Flags parameter value is QDC_DATABASE_CURRENT.</para>
	/// <para>
	/// If the Flags parameter value is set to QDC_DATABASE_CURRENT, the pCurrentTopologyId parameter must not be <c>NULL</c>. If the
	/// Flags parameter value is not set to QDC_DATABASE_CURRENT, the pCurrentTopologyId parameter value must be <c>NULL</c>.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags that are specified is invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INSUFFICIENT_BUFFER</term>
	/// <term>The supplied path and mode buffer are too small.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// As the GetDisplayConfigBufferSizes function can only determine the required array size at a particular moment in time, it is
	/// possible that between calls to <c>GetDisplayConfigBufferSizes</c> and <c>QueryDisplayConfig</c> the system configuration will
	/// change and the provided array sizes will no longer be sufficient to store the new path data. In this situation,
	/// <c>QueryDisplayConfig</c> fails with ERROR_INSUFFICIENT_BUFFER, and the caller should call <c>GetDisplayConfigBufferSizes</c>
	/// again to get the new array sizes. The caller should then allocate the correct amount of memory.
	/// </para>
	/// <para>
	/// <c>QueryDisplayConfig</c> returns paths in the path array that the pPathInfoArray parameter specifies and the source and target
	/// modes in the mode array that the pModeInfoArray parameter specifies. <c>QueryDisplayConfig</c> always returns paths in path
	/// priority order. If QDC_ALL_PATHS is set in the Flags parameter, <c>QueryDisplayConfig</c> returns all the inactive paths after
	/// the active paths.
	/// </para>
	/// <para>
	/// Full path, source mode, and target mode information is available for all active paths. The <c>ModeInfoIdx</c> members in the
	/// DISPLAYCONFIG_PATH_SOURCE_INFO and DISPLAYCONFIG_PATH_TARGET_INFO structures for the source and target are set up for these
	/// active paths. For inactive paths, returned source and target mode information is not available; therefore, the target information
	/// in the path structure is set to default values, and the source and target mode indexes are marked as invalid. For database
	/// queries, if the current connect monitors have an entry, <c>QueryDisplayConfig</c> returns full path, source mode, and target mode
	/// information (same as for active paths). However, if the database does not have a entry, <c>QueryDisplayConfig</c> returns just
	/// the path information with the default target details (same as for inactive paths).
	/// </para>
	/// <para>
	/// For an example of how source and target mode information relates to path information, see Relationship of Mode Information to
	/// Path Information.
	/// </para>
	/// <para>
	/// The caller can use DisplayConfigGetDeviceInfo to obtain additional information about the source or target device, for example,
	/// the monitor names and monitor preferred mode and source device name.
	/// </para>
	/// <para>
	/// If a target is currently being force projected, the <c>statusFlags</c> member of the DISPLAYCONFIG_PATH_TARGET_INFO structure has
	/// one of the DISPLAYCONFIG_TARGET_FORCED_XXX flags set.
	/// </para>
	/// <para>
	/// If the QDC_DATABASE_CURRENT flag is set in the Flags parameter, <c>QueryDisplayConfig</c> returns the topology identifier of the
	/// active database topology in the variable that the pCurrentTopologyId parameter points to. If the QDC_ALL_PATHS or
	/// QDC_ONLY_ACTIVE_PATHS flag is set in the Flags parameter, the pCurrentTopologyId parameter must be set to <c>NULL</c>; otherwise,
	/// <c>QueryDisplayConfig</c> returns ERROR_INVALID_PARAMETER.
	/// </para>
	/// <para>
	/// If a caller calls <c>QueryDisplayConfig</c> with the QDC_DATABASE_CURRENT flag set in the Flags parameter,
	/// <c>QueryDisplayConfig</c> initializes the DISPLAYCONFIG_2DREGION structure that is specified in the <c>totalSize</c> member of
	/// the DISPLAYCONFIG_VIDEO_SIGNAL_INFO structure to zeros and does not complete DISPLAYCONFIG_2DREGION.
	/// </para>
	/// <para>
	/// The DEVMODE structure that is returned by the EnumDisplaySettings Win32 function (described in the Windows SDK documentation)
	/// contains information that relates to both the source and target modes. However, the CCD APIs explicitly separate the source and
	/// target mode components.
	/// </para>
	/// <para>DPI Virtualization</para>
	/// <para>
	/// This API does not participate in DPI virtualization. All sizes in the DEVMODE structure are in terms of physical pixels, and are
	/// not related to the calling context.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-querydisplayconfig LONG QueryDisplayConfig( UINT32 flags,
	// UINT32 *numPathArrayElements, DISPLAYCONFIG_PATH_INFO *pathArray, UINT32 *numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO
	// *modeInfoArray, DISPLAYCONFIG_TOPOLOGY_ID *currentTopologyId );
	[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("winuser.h", MSDNShortId = "b1792d7f-f216-4250-a6b6-a11b251a9cec")]
	public static extern Win32Error QueryDisplayConfig(QDC flags, ref uint numPathArrayElements, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] DISPLAYCONFIG_PATH_INFO[] pathArray,
		ref uint numModeInfoArrayElements, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId = default);

	/// <summary>
	/// The <c>QueryDisplayConfig</c> function retrieves information about all possible display paths for all display devices, or views,
	/// in the current setting.
	/// </summary>
	/// <param name="flags">
	/// <para>The type of information to retrieve. The value for the Flags parameter must be one of the following values.</para>
	/// <para>QDC_ALL_PATHS</para>
	/// <para>All the possible path combinations of sources to targets.</para>
	/// <para>
	/// <c>Note</c> In the case of any temporary modes, the QDC_ALL_PATHS setting means the mode data returned may not be the same as
	/// that which is stored in the persistence database.
	/// </para>
	/// <para>QDC_ONLY_ACTIVE_PATHS</para>
	/// <para>Currently active paths only.</para>
	/// <para>
	/// <c>Note</c> In the case of any temporary modes, the QDC_ONLY_ACTIVE_PATHS setting means the mode data returned may not be the
	/// same as that which is stored in the persistence database.
	/// </para>
	/// <para>QDC_DATABASE_CURRENT</para>
	/// <para>Active path as defined in the CCD database for the currently connected displays.</para>
	/// </param>
	/// <param name="numPathArrayElements">
	/// Pointer to a variable that contains the number of elements in pPathInfoArray. This parameter cannot be <c>NULL</c>. If
	/// <c>QueryDisplayConfig</c> returns ERROR_SUCCESS, pNumPathInfoElements is updated with the number of valid entries in pPathInfoArray.
	/// </param>
	/// <param name="pathArray">
	/// Pointer to a variable that contains an array of DISPLAYCONFIG_PATH_INFO elements. Each element in pPathInfoArray describes a
	/// single path from a source to a target. The source and target mode information indexes are only valid in combination with the
	/// pmodeInfoArray tables that are returned for the API at the same time. This parameter cannot be <c>NULL</c>. The pPathInfoArray is
	/// always returned in path priority order. For more information about path priority order, see Path Priority Order.
	/// </param>
	/// <param name="numModeInfoArrayElements">
	/// Pointer to a variable that specifies the number in element of the mode information table. This parameter cannot be <c>NULL</c>.
	/// If <c>QueryDisplayConfig</c> returns ERROR_SUCCESS, pNumModeInfoArrayElements is updated with the number of valid entries in pModeInfoArray.
	/// </param>
	/// <param name="modeInfoArray">
	/// Pointer to a variable that contains an array of DISPLAYCONFIG_MODE_INFO elements. This parameter cannot be <c>NULL</c>.
	/// </param>
	/// <param name="currentTopologyId">
	/// <para>
	/// Pointer to a variable that receives the identifier of the currently active topology in the CCD database. For a list of possible
	/// values, see the DISPLAYCONFIG_TOPOLOGY_ID enumerated type.
	/// </para>
	/// <para>The pCurrentTopologyId parameter is only set when the Flags parameter value is QDC_DATABASE_CURRENT.</para>
	/// <para>
	/// If the Flags parameter value is set to QDC_DATABASE_CURRENT, the pCurrentTopologyId parameter must not be <c>NULL</c>. If the
	/// Flags parameter value is not set to QDC_DATABASE_CURRENT, the pCurrentTopologyId parameter value must be <c>NULL</c>.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags that are specified is invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INSUFFICIENT_BUFFER</term>
	/// <term>The supplied path and mode buffer are too small.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// As the GetDisplayConfigBufferSizes function can only determine the required array size at a particular moment in time, it is
	/// possible that between calls to <c>GetDisplayConfigBufferSizes</c> and <c>QueryDisplayConfig</c> the system configuration will
	/// change and the provided array sizes will no longer be sufficient to store the new path data. In this situation,
	/// <c>QueryDisplayConfig</c> fails with ERROR_INSUFFICIENT_BUFFER, and the caller should call <c>GetDisplayConfigBufferSizes</c>
	/// again to get the new array sizes. The caller should then allocate the correct amount of memory.
	/// </para>
	/// <para>
	/// <c>QueryDisplayConfig</c> returns paths in the path array that the pPathInfoArray parameter specifies and the source and target
	/// modes in the mode array that the pModeInfoArray parameter specifies. <c>QueryDisplayConfig</c> always returns paths in path
	/// priority order. If QDC_ALL_PATHS is set in the Flags parameter, <c>QueryDisplayConfig</c> returns all the inactive paths after
	/// the active paths.
	/// </para>
	/// <para>
	/// Full path, source mode, and target mode information is available for all active paths. The <c>ModeInfoIdx</c> members in the
	/// DISPLAYCONFIG_PATH_SOURCE_INFO and DISPLAYCONFIG_PATH_TARGET_INFO structures for the source and target are set up for these
	/// active paths. For inactive paths, returned source and target mode information is not available; therefore, the target information
	/// in the path structure is set to default values, and the source and target mode indexes are marked as invalid. For database
	/// queries, if the current connect monitors have an entry, <c>QueryDisplayConfig</c> returns full path, source mode, and target mode
	/// information (same as for active paths). However, if the database does not have a entry, <c>QueryDisplayConfig</c> returns just
	/// the path information with the default target details (same as for inactive paths).
	/// </para>
	/// <para>
	/// For an example of how source and target mode information relates to path information, see Relationship of Mode Information to
	/// Path Information.
	/// </para>
	/// <para>
	/// The caller can use DisplayConfigGetDeviceInfo to obtain additional information about the source or target device, for example,
	/// the monitor names and monitor preferred mode and source device name.
	/// </para>
	/// <para>
	/// If a target is currently being force projected, the <c>statusFlags</c> member of the DISPLAYCONFIG_PATH_TARGET_INFO structure has
	/// one of the DISPLAYCONFIG_TARGET_FORCED_XXX flags set.
	/// </para>
	/// <para>
	/// If the QDC_DATABASE_CURRENT flag is set in the Flags parameter, <c>QueryDisplayConfig</c> returns the topology identifier of the
	/// active database topology in the variable that the pCurrentTopologyId parameter points to. If the QDC_ALL_PATHS or
	/// QDC_ONLY_ACTIVE_PATHS flag is set in the Flags parameter, the pCurrentTopologyId parameter must be set to <c>NULL</c>; otherwise,
	/// <c>QueryDisplayConfig</c> returns ERROR_INVALID_PARAMETER.
	/// </para>
	/// <para>
	/// If a caller calls <c>QueryDisplayConfig</c> with the QDC_DATABASE_CURRENT flag set in the Flags parameter,
	/// <c>QueryDisplayConfig</c> initializes the DISPLAYCONFIG_2DREGION structure that is specified in the <c>totalSize</c> member of
	/// the DISPLAYCONFIG_VIDEO_SIGNAL_INFO structure to zeros and does not complete DISPLAYCONFIG_2DREGION.
	/// </para>
	/// <para>
	/// The DEVMODE structure that is returned by the EnumDisplaySettings Win32 function (described in the Windows SDK documentation)
	/// contains information that relates to both the source and target modes. However, the CCD APIs explicitly separate the source and
	/// target mode components.
	/// </para>
	/// <para>DPI Virtualization</para>
	/// <para>
	/// This API does not participate in DPI virtualization. All sizes in the DEVMODE structure are in terms of physical pixels, and are
	/// not related to the calling context.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-querydisplayconfig LONG QueryDisplayConfig( UINT32 flags,
	// UINT32 *numPathArrayElements, DISPLAYCONFIG_PATH_INFO *pathArray, UINT32 *numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO
	// *modeInfoArray, DISPLAYCONFIG_TOPOLOGY_ID *currentTopologyId );
	[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("winuser.h", MSDNShortId = "b1792d7f-f216-4250-a6b6-a11b251a9cec")]
	public static extern Win32Error QueryDisplayConfig(QDC flags, ref uint numPathArrayElements, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] DISPLAYCONFIG_PATH_INFO[] pathArray,
		ref uint numModeInfoArrayElements, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, out DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId);

	/// <summary>
	/// The <c>QueryDisplayConfig</c> function retrieves information about all possible display paths for all display devices, or views,
	/// in the current setting. This method also calls GetDisplayConfigBufferSizes to determine output sizing.
	/// </summary>
	/// <param name="flags">
	/// <para>The type of information to retrieve. The value for the Flags parameter must be one of the following values.</para>
	/// <para>QDC_ALL_PATHS</para>
	/// <para>All the possible path combinations of sources to targets.</para>
	/// <para>
	/// <c>Note</c> In the case of any temporary modes, the QDC_ALL_PATHS setting means the mode data returned may not be the same as
	/// that which is stored in the persistence database.
	/// </para>
	/// <para>QDC_ONLY_ACTIVE_PATHS</para>
	/// <para>Currently active paths only.</para>
	/// <para>
	/// <c>Note</c> In the case of any temporary modes, the QDC_ONLY_ACTIVE_PATHS setting means the mode data returned may not be the
	/// same as that which is stored in the persistence database.
	/// </para>
	/// <para>QDC_DATABASE_CURRENT</para>
	/// <para>Active path as defined in the CCD database for the currently connected displays.</para>
	/// </param>
	/// <param name="pathArray">
	/// The resulting array of DISPLAYCONFIG_PATH_INFO elements. Each element in pPathInfoArray describes a single path from a source to
	/// a target. The source and target mode information indexes are only valid in combination with the pmodeInfoArray tables that are
	/// returned for the API at the same time. This parameter cannot be <c>NULL</c>. The pPathInfoArray is always returned in path
	/// priority order. For more information about path priority order, see Path Priority Order.
	/// </param>
	/// <param name="modeInfoArray">The resulting array of DISPLAYCONFIG_MODE_INFO elements.</param>
	/// <param name="currentTopologyId">
	/// <para>
	/// Pointer to a variable that receives the identifier of the currently active topology in the CCD database. For a list of possible
	/// values, see the DISPLAYCONFIG_TOPOLOGY_ID enumerated type.
	/// </para>
	/// <para>The pCurrentTopologyId parameter is only set when the Flags parameter value is QDC_DATABASE_CURRENT.</para>
	/// <para>
	/// If the Flags parameter value is set to QDC_DATABASE_CURRENT, the pCurrentTopologyId parameter must not be <c>NULL</c>. If the
	/// Flags parameter value is not set to QDC_DATABASE_CURRENT, the pCurrentTopologyId parameter value must be <c>NULL</c>.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags that are specified is invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INSUFFICIENT_BUFFER</term>
	/// <term>The supplied path and mode buffer are too small.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// <c>QueryDisplayConfig</c> returns paths in the path array that the pPathInfoArray parameter specifies and the source and target
	/// modes in the mode array that the pModeInfoArray parameter specifies. <c>QueryDisplayConfig</c> always returns paths in path
	/// priority order. If QDC_ALL_PATHS is set in the Flags parameter, <c>QueryDisplayConfig</c> returns all the inactive paths after
	/// the active paths.
	/// </para>
	/// <para>
	/// Full path, source mode, and target mode information is available for all active paths. The <c>ModeInfoIdx</c> members in the
	/// DISPLAYCONFIG_PATH_SOURCE_INFO and DISPLAYCONFIG_PATH_TARGET_INFO structures for the source and target are set up for these
	/// active paths. For inactive paths, returned source and target mode information is not available; therefore, the target information
	/// in the path structure is set to default values, and the source and target mode indexes are marked as invalid. For database
	/// queries, if the current connect monitors have an entry, <c>QueryDisplayConfig</c> returns full path, source mode, and target mode
	/// information (same as for active paths). However, if the database does not have a entry, <c>QueryDisplayConfig</c> returns just
	/// the path information with the default target details (same as for inactive paths).
	/// </para>
	/// <para>
	/// For an example of how source and target mode information relates to path information, see Relationship of Mode Information to
	/// Path Information.
	/// </para>
	/// <para>
	/// The caller can use DisplayConfigGetDeviceInfo to obtain additional information about the source or target device, for example,
	/// the monitor names and monitor preferred mode and source device name.
	/// </para>
	/// <para>
	/// If a target is currently being force projected, the <c>statusFlags</c> member of the DISPLAYCONFIG_PATH_TARGET_INFO structure has
	/// one of the DISPLAYCONFIG_TARGET_FORCED_XXX flags set.
	/// </para>
	/// <para>
	/// If the QDC_DATABASE_CURRENT flag is set in the Flags parameter, <c>QueryDisplayConfig</c> returns the topology identifier of the
	/// active database topology in the variable that the pCurrentTopologyId parameter points to. If the QDC_ALL_PATHS or
	/// QDC_ONLY_ACTIVE_PATHS flag is set in the Flags parameter, the pCurrentTopologyId parameter must be set to <c>NULL</c>; otherwise,
	/// <c>QueryDisplayConfig</c> returns ERROR_INVALID_PARAMETER.
	/// </para>
	/// <para>
	/// If a caller calls <c>QueryDisplayConfig</c> with the QDC_DATABASE_CURRENT flag set in the Flags parameter,
	/// <c>QueryDisplayConfig</c> initializes the DISPLAYCONFIG_2DREGION structure that is specified in the <c>totalSize</c> member of
	/// the DISPLAYCONFIG_VIDEO_SIGNAL_INFO structure to zeros and does not complete DISPLAYCONFIG_2DREGION.
	/// </para>
	/// <para>
	/// The DEVMODE structure that is returned by the EnumDisplaySettings Win32 function (described in the Windows SDK documentation)
	/// contains information that relates to both the source and target modes. However, the CCD APIs explicitly separate the source and
	/// target mode components.
	/// </para>
	/// <para>DPI Virtualization</para>
	/// <para>
	/// This API does not participate in DPI virtualization. All sizes in the DEVMODE structure are in terms of physical pixels, and are
	/// not related to the calling context.
	/// </para>
	/// </remarks>
	[PInvokeData("winuser.h", MSDNShortId = "b1792d7f-f216-4250-a6b6-a11b251a9cec")]
	public static Win32Error QueryDisplayConfig(QDC flags, out DISPLAYCONFIG_PATH_INFO[] pathArray, out DISPLAYCONFIG_MODE_INFO[] modeInfoArray, out DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId)
	{
		Win32Error err;
		do
		{
			err = GetDisplayConfigBufferSizes(flags, out var cPath, out var cMode);
			pathArray = new DISPLAYCONFIG_PATH_INFO[err.Failed ? 0 : cPath];
			modeInfoArray = new DISPLAYCONFIG_MODE_INFO[err.Failed ? 0 : cMode];
			currentTopologyId = 0;
			if (err.Failed) return err;
			if (flags.IsFlagSet(QDC.QDC_DATABASE_CURRENT))
				err = QueryDisplayConfig(flags, ref cPath, pathArray, ref cMode, modeInfoArray, out currentTopologyId);
			else
				err = QueryDisplayConfig(flags, ref cPath, pathArray, ref cMode, modeInfoArray);
			if (err.Succeeded || err != Win32Error.ERROR_INSUFFICIENT_BUFFER) return err;
		} while (err == Win32Error.ERROR_INSUFFICIENT_BUFFER);
		return err;
	}

	/// <summary>
	/// The <c>SetDisplayConfig</c> function modifies the display topology, source, and target modes by exclusively enabling the
	/// specified paths in the current session.
	/// </summary>
	/// <param name="numPathArrayElements">Number of elements in pathArray.</param>
	/// <param name="pathArray">
	/// Array of all display paths that are to be set. Only the paths within this array that have the DISPLAYCONFIG_PATH_ACTIVE flag set
	/// in the <c>flags</c> member of DISPLAYCONFIG_PATH_INFO are set. This parameter can be <c>NULL</c>. The order in which active paths
	/// appear in this array determines the path priority. For more information about path priority order, see Path Priority Order.
	/// </param>
	/// <param name="numModeInfoArrayElements">Number of elements in modeInfoArray.</param>
	/// <param name="modeInfoArray">
	/// Array of display source and target mode information (DISPLAYCONFIG_MODE_INFO) that is referenced by the <c>modeInfoIdx</c> member
	/// of DISPLAYCONFIG_PATH_SOURCE_INFO and DISPLAYCONFIG_PATH_TARGET_INFO element of path information from pathArray. This parameter
	/// can be <c>NULL</c>.
	/// </param>
	/// <param name="flags">
	/// <para>
	/// A bitwise OR of flag values that indicates the behavior of this function. This parameter can be one the following values, or a
	/// combination of the following values; 0 is not valid.
	/// </para>
	/// <para>SDC_APPLY</para>
	/// <para>The resulting topology, source, and target mode is set.</para>
	/// <para>SDC_NO_OPTIMIZATION</para>
	/// <para>
	/// A modifier to the SDC_APPLY flag. This causes the change mode to be forced all the way down to the driver for each active display.
	/// </para>
	/// <para>SDC_USE_SUPPLIED_DISPLAY_CONFIG</para>
	/// <para>
	/// The topology, source, and target mode information that are supplied in the pathArray and the modeInfoArray parameters are used,
	/// rather than looking up the configuration in the database.
	/// </para>
	/// <para>SDC_SAVE_TO_DATABASE</para>
	/// <para>The resulting topology, source, and target mode are saved to the database.</para>
	/// <para>SDC_VALIDATE</para>
	/// <para>The system tests for the requested topology, source, and target mode information to determine whether it can be set.</para>
	/// <para>SDC_ALLOW_CHANGES</para>
	/// <para>
	/// If required, the function can modify the specified source and target mode information in order to create a functional display
	/// path set.
	/// </para>
	/// <para>SDC_TOPOLOGY_CLONE</para>
	/// <para>The caller requests the last clone configuration from the persistence database.</para>
	/// <para>SDC_TOPOLOGY_EXTEND</para>
	/// <para>The caller requests the last extended configuration from the persistence database.</para>
	/// <para>SDC_TOPOLOGY_INTERNAL</para>
	/// <para>The caller requests the last internal configuration from the persistence database.</para>
	/// <para>SDC_TOPOLOGY_EXTERNAL</para>
	/// <para>The caller requests the last external configuration from the persistence database.</para>
	/// <para>SDC_TOPOLOGY_SUPPLIED</para>
	/// <para>
	/// The caller provides the path data so the function only queries the persistence database to find and use the source and target mode.
	/// </para>
	/// <para>SDC_USE_DATABASE_CURRENT</para>
	/// <para>
	/// The caller requests a combination of all four SDC_TOPOLOGY_XXX configurations. This value informs the API to set the last known
	/// display configuration for the current connected monitors.
	/// </para>
	/// <para>SDC_PATH_PERSIST_IF_REQUIRED</para>
	/// <para>
	/// When the function processes a SDC_TOPOLOGY_XXX request, it can force path persistence on a target to satisfy the request if
	/// necessary. For information about the other flags that this flag can be combined with, see the following list.
	/// </para>
	/// <para>SDC_FORCE_MODE_ENUMERATION</para>
	/// <para>
	/// The caller requests that the driver is given an opportunity to update the GDI mode list while <c>SetDisplayConfig</c> sets the
	/// new display configuration. This flag value is only valid when the SDC_USE_SUPPLIED_DISPLAY_CONFIG and SDC_APPLY flag values are
	/// also specified.
	/// </para>
	/// <para>SDC_ALLOW_PATH_ORDER_CHANGES</para>
	/// <para>
	/// A modifier to the SDC_TOPOLOGY_SUPPLIED flag that indicates that <c>SetDisplayConfig</c> should ignore the path order of the
	/// supplied topology when searching the database. When this flag is set, the topology set is the most recent topology that contains
	/// all the paths regardless of the path order.
	/// </para>
	/// <para>The following list contains valid combinations of values for the Flags parameter:</para>
	/// <list type="bullet">
	/// <item>
	/// <term>Either SDC_APPLY or SDC_VALIDATE must be set, but not both.</term>
	/// </item>
	/// <item>
	/// <term>
	/// Either SDC_USE_SUPPLIED_DISPLAY_CONFIG or any combinations of SDC_TOPOLOGY_XXX must be set. SDC_USE_SUPPLIED_DISPLAY_CONFIG
	/// cannot be set with any SDC_TOPOLOGY_XXX flag.
	/// </term>
	/// </item>
	/// <item>
	/// <term>SDC_NO_OPTIMIZATION can only be set with SDC_APPLY.</term>
	/// </item>
	/// <item>
	/// <term>SDC_ALLOW_CHANGES is allowed with any other valid combination.</term>
	/// </item>
	/// <item>
	/// <term>SDC_SAVE_TO_DATABASE can only be set with SDC_USE_SUPPLIED_DISPLAY_CONFIG.</term>
	/// </item>
	/// <item>
	/// <term>SDC_PATH_PERSIST_IF_REQUIRED cannot be used with SDC_USE_SUPPLIED_DISPLAY_CONFIG or SDC_TOPOLOGY_SUPPLIED.</term>
	/// </item>
	/// <item>
	/// <term>SDC_FORCE_MODE_ENUMERATION is only valid when SDC_APPLY and SDC_USE_SUPPLIED_DISPLAY_CONFIG are specified.</term>
	/// </item>
	/// <item>
	/// <term>SDC_ALLOW_PATH_ORDER_CHANGES is allowed only when SDC_TOPOLOGY_SUPPLIED is specified.</term>
	/// </item>
	/// <item>
	/// <term>
	/// SDC_TOPOLOGY_SUPPLIED cannot be used with any other SDC_TOPOLOGY_XXX flag. Because of a validation issue, if a caller violates
	/// this rule, <c>SetDisplayConfig</c> does not fail. However, <c>SetDisplayConfig</c> ignores the SDC_TOPOLOGY_SUPPLIED flag.
	/// </term>
	/// </item>
	/// </list>
	/// <para>
	/// SDC_TOPOLOGY_XXX flags can be used in combinations. For example, if SDC_TOPOLOGY_CLONE and SDC_TOPOLOGY_EXTEND are set, the API
	/// uses the most recent clone or extend topology, which every topology was set with most recently for the current connected monitors.
	/// </para>
	/// </param>
	/// <returns>
	/// <para>The function returns one of the following return codes.</para>
	/// <list type="table">
	/// <listheader>
	/// <term>Return code</term>
	/// <term>Description</term>
	/// </listheader>
	/// <item>
	/// <term>ERROR_SUCCESS</term>
	/// <term>The function succeeded.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_INVALID_PARAMETER</term>
	/// <term>The combination of parameters and flags specified is invalid.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_NOT_SUPPORTED</term>
	/// <term>
	/// The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function
	/// is only supported on a system with a WDDM driver running.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_ACCESS_DENIED</term>
	/// <term>
	/// The caller does not have access to the console session. This error occurs if the calling process does not have access to the
	/// current desktop or is running on a remote session.
	/// </term>
	/// </item>
	/// <item>
	/// <term>ERROR_GEN_FAILURE</term>
	/// <term>An unspecified error occurred.</term>
	/// </item>
	/// <item>
	/// <term>ERROR_BAD_CONFIGURATION</term>
	/// <term>The function could not find a workable solution for the source and target modes that the caller did not specify.</term>
	/// </item>
	/// </list>
	/// </returns>
	/// <remarks>
	/// <para>
	/// The <c>SetDisplayConfig</c> function takes the active display paths with any specified source and target mode information and
	/// uses best mode logic to generate any missing source and target mode information. This function then sets the complete display path.
	/// </para>
	/// <para>
	/// The <c>ModeInfoIdx</c> members in the DISPLAYCONFIG_PATH_SOURCE_INFO and DISPLAYCONFIG_PATH_TARGET_INFO structures are used to
	/// indicate whether source and target mode are supplied for a given active path. If the index value is
	/// DISPLAYCONFIG_PATH_MODE_IDX_INVALID for either, this indicates the mode information is not being specified. It is valid for the
	/// path plus source mode or the path plus source and target mode information to be specified for a given path. However, it is not
	/// valid for the path plus target mode to be specified without the source mode.
	/// </para>
	/// <para>
	/// The source and target modes for each source and target identifiers can only appear in the modeInfoArray array once. For example,
	/// a source mode for source identifier S1 can only appear in the table once; if multiple paths reference the same source, they have
	/// to use the same <c>ModeInfoIdx</c>.
	/// </para>
	/// <para>
	/// The expectation is that most callers use QueryDisplayConfig to get the current configuration along with other valid possibilities
	/// and then use <c>SetDisplayConfig</c> to test and set the configuration.
	/// </para>
	/// <para>The order in which the active paths appear in the PathArray array determines the path priority.</para>
	/// <para>
	/// By default, <c>SetDisplayConfig</c> never changes any supplied path, source mode, or target mode information. If best mode logic
	/// cannot find a solution without changing the specified display path information, <c>SetDisplayConfig</c> fails with
	/// ERROR_BAD_CONFIGURATION. In this case, the caller should specify the SDC_ALLOW_CHANGES flag to allow the function to tweak some
	/// of the specified source and mode details to allow the display path change to be successful.
	/// </para>
	/// <para>
	/// If the specified or calculated source and target modes have the same dimensions, <c>SetDisplayConfig</c> automatically sets the
	/// path scaling to DISPLAYCONFIG_PPR_IDENTITY before setting the display path and saving it in the database. For information about
	/// how <c>SetDisplayConfig</c> handles scaling, see Scaling the Desktop Image.
	/// </para>
	/// <para>
	/// When the caller specifies the SDC_USE_SUPPLIED_DISPLAY_CONFIG flag to set a clone path and if any source mode indexes are invalid
	/// in the path array, <c>SetDisplayConfig</c> determines that all of the source mode indexes from that source are invalid.
	/// <c>SetDisplayConfig</c> uses the best mode logic to determine the source mode information.
	/// </para>
	/// <para>
	/// Except for the SDC_TOPOLOGY_SUPPLIED flag (for more information about SDC_TOPOLOGY_SUPPLIED, see the following paragraph), the
	/// SDC_TOPOLOGY_XXX flags set last display path settings, including the source and target mode information for that topology type.
	/// For information about valid SDC_TOPOLOGY_XXX flag combinations, see the Flags parameter description. The pathArray and
	/// modeInfoArray parameters must be <c>NULL</c>, and their associated sizes must be zero. For example, if SDC_TOPOLOGY_CLONE and
	/// SDC_TOPOLOGY_EXTEND are set, this function uses the most recent clone or extend display path configuration. If a single topology
	/// type is requested, the last configuration of that type is used. If that topology had never been set before,
	/// <c>SetDisplayConfig</c> uses the best topology logic to find the best topology, and then best mode logic to find the best source
	/// and target mode to use. If a combination of the topology flags had been set and none of them had database entries, the following
	/// priority is used. For laptops: clone, extend, internal, and then external; for desktops the priority is extend and then clone.
	/// </para>
	/// <para>
	/// The caller can specify the SDC_TOPOLOGY_SUPPLIED flag to indicate that it sets just the path information (topology) and requests
	/// that <c>SetDisplayConfig</c> obtains and then uses the source and target mode information from the persistence database. If the
	/// active paths that the caller supplies do not have an entry in the persistence database, <c>SetDisplayConfig</c> fails. In this
	/// case, if the caller calls <c>SetDisplayConfig</c> again with the same path data but with the SDC_USE_SUPPLIED_DISPLAY_CONFIG flag
	/// set, <c>SetDisplayConfig</c> uses best mode logic to create the source and target mode information. When the caller specifies
	/// SDC_TOPOLOGY_SUPPLIED, the caller must set the numModeInfoArrayElements parameter to zero and the modeInfoArray parameter to
	/// <c>NULL</c>; however, the caller must set the pathArray and numPathArrayElements parameters for the path information that the
	/// caller requires. The caller must mark all the source and target mode indexes as invalid (DISPLAYCONFIG_PATH_MODE_IDX_INVALID) in
	/// this path data.
	/// </para>
	/// <para>
	/// The following table provides some common scenarios where <c>SetDisplayConfig</c> is called along with the flag combinations that
	/// the caller passes to the Flags parameter to achieve the scenarios.
	/// </para>
	/// <list type="table">
	/// <listheader>
	/// <term>Scenario</term>
	/// <term>Flag combination</term>
	/// </listheader>
	/// <item>
	/// <term>Test whether a specified display configuration is supported on the computer</term>
	/// <term>SDC_VALIDATE | SDC_USE_SUPPLIED_DISPLAY_CONFIG</term>
	/// </item>
	/// <item>
	/// <term>Set a specified display configuration and save to the database</term>
	/// <term>SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_SAVE_TO_DATABASE</term>
	/// </item>
	/// <item>
	/// <term>Set a temporary display configuration (that is, the display configuration will not be saved)</term>
	/// <term>SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG</term>
	/// </item>
	/// <item>
	/// <term>Test whether clone is supported on the computer</term>
	/// <term>SDC_VALIDATE | SDC_TOPOLOGY_CLONE</term>
	/// </item>
	/// <item>
	/// <term>Set clone topology</term>
	/// <term>SDC_APPLY | SDC_TOPOLOGY_CLONE</term>
	/// </item>
	/// <item>
	/// <term>Set clone topology and allow path persistence to be enabled if required to satisfy the request</term>
	/// <term>SDC_APPLY | SDC_TOPOLOGY_CLONE | SDC_PATH_PERSIST_IF_REQUIRED</term>
	/// </item>
	/// <item>
	/// <term>Return from a temporary mode to the last saved display configuration</term>
	/// <term>SDC_APPLY| SDC_USE_DATABASE_CURRENT</term>
	/// </item>
	/// <item>
	/// <term>
	/// Given only the path information, set the display configuration with the source and target information from the database for the
	/// paths and ignore the path order
	/// </term>
	/// <term>SDC_APPLY | SDC_TOPOLOGY_SUPPLIED | SDC_ALLOW_PATH_ORDER_CHANGES</term>
	/// </item>
	/// </list>
	/// <para>DPI Virtualization</para>
	/// <para>
	/// This API does not participate in DPI virtualization. All sizes in the DEVMODE structure are in terms of physical pixels, and are
	/// not related to the calling context.
	/// </para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setdisplayconfig LONG SetDisplayConfig( UINT32
	// numPathArrayElements, DISPLAYCONFIG_PATH_INFO *pathArray, UINT32 numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO *modeInfoArray,
	// UINT32 flags );
	[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("winuser.h", MSDNShortId = "9f649fa0-ffb2-44c6-9a66-049f888e3b04")]
	public static extern Win32Error SetDisplayConfig(uint numPathArrayElements, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Optional] DISPLAYCONFIG_PATH_INFO[]? pathArray,
		uint numModeInfoArrayElements, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Optional] DISPLAYCONFIG_MODE_INFO[]? modeInfoArray, SDC flags);
}